package com.deep.spring.v31;

/**
 * @author sw
 * @create 2022-12-16 17:09
 */

import org.springframework.beans.BeanUtils;

import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;

public class MyBeanUtils {

    //模仿BeanUtils.copyProperties()写一个自己的copyProperties方法，唯一的区别就是最后一个参数的类型由String改为MyFunctional
    public static <T> void copyProperties(Object source, Object target, MyFunctional<T>... ignoreProperties) {
        String[] ignorePropertieNames = null;
        if (ignoreProperties != null && ignoreProperties.length > 0) {
            ignorePropertieNames = new String[ignoreProperties.length];
            for (int i = 0; i < ignoreProperties.length; i++) {
                MyFunctional lambda = ignoreProperties[i];
                //根据lambda表达式得到字段名
                ignorePropertieNames[i] = getPropertyName(lambda);
            }
        }
        //最终还是调用Spring的工具类：
        BeanUtils.copyProperties(source, target, ignorePropertieNames);
    }

    //获取lamba表达式中调用方法对应的属性名，比如lamba表达式：User::getSex，则返回字符串"sex"
    public static <T> String getPropertyName(MyFunctional<T> lambda) {
        try {
            //writeReplace从哪里来的？后面会讲到
            Method method = lambda.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            //调用writeReplace()方法，返回一个SerializedLambda对象
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(lambda);
            //得到lambda表达式中调用的方法名，如 "User::getSex"，则得到的是"getSex"
            String getterMethod = serializedLambda.getImplMethodName();
            //去掉”get"前缀，最终得到字段名“sex"
            String fieldName = Introspector.decapitalize(getterMethod.replace("get", ""));
            return fieldName;
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

}

